home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************/
- /* Copyright(c) 1987, 1992 by BBN Systems and Technologies, */
- /* A Division of Bolt Beranek and Newman Inc. */
- /* */
- /* RDP implementation for 4.2/4.3bsd by Craig Partridge */
- /* */
- /* Permission to use, copy, modify, distribute, and sell this software */
- /* and its documentation for any purpose is hereby granted without fee, */
- /* provided that the above copyright notice and this permission appear */
- /* in all copies and in supporting documentation, and that the name of */
- /* Bolt Beranek and Newman Inc. not be used in advertising or */
- /* publicity pertaining to distribution of the software without */
- /* specific, written prior permission. BBN makes no representations */
- /* about the suitability of this software for any purposes. It is */
- /* provided "AS IS" without express or implied warranties. */
- /**************************************************************************/
-
- #include "../h/param.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/mbuf.h"
- #include "../h/protosw.h"
- #include "../h/socket.h"
- #include "../h/socketvar.h"
- #include "../h/stat.h"
- #include "../h/errno.h"
-
- #include "../net/if.h"
- #include "../net/route.h"
-
- #include "../netinet/in.h"
- #include "../netinet/in_pcb.h"
- #include "../netinet/in_systm.h"
- #include "../netinet/ip.h"
- #include "../netinet/ip_var.h"
- #include "../netinet/ip_icmp.h"
-
- #include "../netinet/rdp.h"
- #include "../netinet/rdp_var.h"
- #include "../netinet/rdp_conf.h"
- #include "../netinet/rdp_ip.h"
-
- /* head of pcb queue */
- struct inpcb rdb;
-
- /* serial number counter */
- u_long rdpserial;
-
- /* rdp statistics */
-
- struct rdpstats rdp_info;
-
- /*
- * max seg size. have treated it as an indication of how large a packet
- * we are willing to buffer and have not tried to use it as a way of
- * finding optimal packet size for connection.
- */
- u_short rdp_mtu = 1024;
-
- /*
- * timer backoff table for starting connections
- * after that we use rtt. Can tune table for environment...
- *
- * currently tried to tune it for local net (2 tries, then long timeouts
- * for wide-area network).
- */
-
- short rdp_start[] =
- {
- 1, 3, 12, 28, 60, 128
- };
-
- static short rdp_tryinit = sizeof(rdp_start)/sizeof(rdp_start[0]);
-
-
- /**************************************************************************/
- /* init routine */
- /**************************************************************************/
-
- rdp_init()
- {
- struct rdphdr rdh;
- static int called = 0;
-
- if (called)
- return;
-
- called++;
-
- #ifdef DEBUG
- printf("rdpcb size =%d, mlen =%d\n",sizeof(struct rdpcb),MLEN);
- printf("rdque size =%d, mlen =%d\n",sizeof(struct rdpque),MLEN);
- #endif DEBUG
-
- rdb.inp_next = rdb.inp_prev = &rdb;
-
- /* choose a random starting place? */
- rdpserial = 1;
-
- #ifdef DEBUG
- printf("rdp_mtu is %d\n",rdp_mtu);
- #endif
-
- /* leave this in -- saves us from dumb mistakes */
- if (sizeof(struct rdpcb) > MLEN)
- {
- panic("rdp_init: rdpcb size");
- }
-
- if (sizeof(struct rdpque) > MLEN)
- {
- panic("rdp_init: rdpque size");
- }
-
- /* compiler woes? */
- if (sizeof(struct rdphdr) != R_HDRSIZE)
- {
- /* may be o.k. -- just that there is trailing junk in header */
- if (((caddr_t)&rdh.rh_sum - (caddr_t)&rdh) != (R_HDRSIZE- 2))
- panic("rdp_init: rdphdr size");
- }
-
- /*
- * IP header + RDP header (including EACKs)
- * must fit in a single mbuf
- */
-
- if ((RI_SIZE + (R_RCVWIN * 4)) > MLEN)
- {
- /* our eacks for packets from remote will exceed mbuf */
- panic("rdp_init: rcv eacks");
- }
-
- if ((RI_SIZE + (R_MAXSND * 4)) > MLEN)
- {
- /* remote's eacks for our packets will exceed mbuf */
- panic("rdp_init: snd eacks");
- }
-
- #ifdef DEBUG
- printf("rdp options: DEBUG");
- #ifdef EACK
- printf(" EACK");
- #endif /* EACK */
- #ifdef INETCKSUM
- printf(" INETCKSUM");
- #endif /* INETCKSUM */
- #ifdef ALTRTT
- printf(" ALTRTT");
- #else
- printf(" OLDRTT");
- #endif /* ALTRTT */
- printf("\n");
- #endif /* DEBUG */
- }
-
-
-
- /**************************************************************************/
- /* usrreq routine -- see BSD Networking Implementation Notes */
- /**************************************************************************/
-
- rdp_usrreq(so,req,m,addr,rights)
- struct socket *so;
- int req;
- struct mbuf *m, *addr, *rights;
- {
- struct inpcb *inp = sotoinpcb(so);
- struct rdpcb *rp;
- int error = 0;
- int s;
-
- s = splnet();
-
- #ifdef BSD4_3
- /* special case -- sigh... */
-
- if (req == PRU_CONTROL)
- return(in_control(so,(int)m,(caddr_t)addr,(struct ifnet *)rights));
- #endif /* BSD4_3 */
-
- /* pre-process and check values */
-
- if ((rights != 0) && rights->m_len)
- {
- error = EINVAL;
- goto done;
- }
-
- switch (req)
- {
- case PRU_ATTACH:
- if (inp != 0)
- {
- error = EINVAL;
- goto done;
- }
- break;
-
- case PRU_DETACH:
- case PRU_BIND:
- case PRU_ABORT:
- case PRU_SENSE:
- case PRU_CONTROL:
- case PRU_SHUTDOWN:
- if (inp == 0)
- {
- error = EINVAL;
- goto done;
- }
- break;
-
- /* these require us to be bound at our end */
- case PRU_SOCKADDR:
- case PRU_CONNECT:
- case PRU_LISTEN:
- if (inp == 0)
- error = EINVAL;
- else if (inp->inp_lport == 0)
- error = in_pcbbind(inp,(struct mbuf *)0);
-
- if (error)
- goto done;
- break;
-
-
- /* these make no sense if we aren't connected? */
- case PRU_DISCONNECT:
- case PRU_ACCEPT:
- case PRU_SEND:
- case PRU_PEERADDR:
- if ((inp ==0) || (inp->inp_lport == 0) || (inp->inp_fport == 0))
- {
- error = EINVAL;
- goto done;
- }
- break;
-
- case PRU_RCVD:
- case PRU_RCVOOB:
- case PRU_SENDOOB:
- case PRU_FASTTIMO:
- case PRU_SLOWTIMO:
- case PRU_CONNECT2:
- case PRU_PROTORCV:
- case PRU_PROTOSEND:
- error = EOPNOTSUPP;
- goto done;
-
- default:
- panic("rdp_usrreq");
- }
-
- if (req != PRU_ATTACH)
- rp = (struct rdpcb *)inp->inp_ppcb;
-
- /* O.K. now we know we are in a vaguely rational world */
-
- switch(req)
- {
- case PRU_ATTACH:
- error = rdp_attach(so);
- break;
-
- case PRU_DETACH:
- error = rdp_detach(so,inp);
- break;
-
- case PRU_BIND:
- error = in_pcbbind(inp,addr);
- break;
-
- case PRU_LISTEN:
- if (rp->rp_state != R_CLOSED)
- error = EISCONN;
- else
- rp->rp_state = R_LISTEN;
- break;
-
- case PRU_CONNECT:
- if (rp->rp_state != R_CLOSED)
- error = EISCONN;
- else
- error = rdp_connect(inp,addr);
- break;
-
- case PRU_ABORT:
- /* detach works as abort would want */
- error = 0;
- (void) rdp_fatal(inp);
- break;
-
- case PRU_DISCONNECT:
- error = rdp_disconnect(inp);
- break;
-
- case PRU_ACCEPT:
- /* someone slammed the door before we accepted */
- if (rp->rp_state != R_OPEN)
- {
- error = ECONNABORTED;
- break;
- }
- else
- (void) in_setpeeraddr(inp,addr);
- break;
-
- case PRU_SHUTDOWN:
- /* not going to send any more -- who cares? */
- socantsendmore(so);
- break;
-
- case PRU_SEND:
- /* now the tough stuff */
- if (rp->rp_state != R_OPEN)
- error = ENOTCONN;
- else
- {
- error = rdp_send(inp,m);
- m = 0;
- }
- break;
-
- #ifndef BSD4_3
- case PRU_CONTROL:
- error = EOPNOTSUPP;
- m = 0;
- break;
- #endif
-
- case PRU_SENSE:
- /* zero m so it isn't freed */
- ((struct stat *)m)->st_blksize = rp->rp_sndbuf;
- m = 0;
- break;
-
- case PRU_SOCKADDR:
- (void) in_setsockaddr(inp,addr);
- break;
-
- case PRU_PEERADDR:
- (void) in_setpeeraddr(inp,addr);
- break;
- }
-
- done:
- if (m != 0)
- (void) m_freem(m);
-
- splx(s);
-
- return(error);
- }
-
- /**************************************************************************/
- /* ctlinput routine */
- /* Berkeley gives too little information to be very useful here */
- /**************************************************************************/
-
- rdp_ctlinput(cmd,addr)
- int cmd;
- #ifndef BSD4_3
- caddr_t *addr;
- #else
- struct sockaddr *addr;
- #endif
- {
- #ifndef BSD4_3
- struct sockaddr_in tmp;
- #endif
- struct sockaddr_in *sin;
- extern u_char inetctlerrmap[];
- extern int rdp_quench(), rdp_fatal();
- #ifdef BSD4_3
- extern int in_rtchange();
- #endif
-
- if ((cmd < 0) || (cmd > PRC_NCMDS))
- return;
-
- #ifndef BSD4_3
- if (((struct icmp *)addr)->icmp_ip.ip_p != IPPROTO_RDP)
- return;
-
- bzero((caddr_t)&tmp,sizeof(tmp));
- tmp.sin_family = AF_INET;
- tmp.sin_addr = ((struct icmp *)addr)->icmp_ip.ip_dst;
- sin = &tmp;
- #else
- sin = (struct sockaddr_in *)addr;
- #endif
-
- if (sin->sin_family != AF_INET)
- return;
-
- switch(cmd)
- {
- case PRC_IFDOWN:
- case PRC_MSGSIZE:
- case PRC_PARAMPROB:
- case PRC_TIMXCEED_INTRANS:
- case PRC_TIMXCEED_REASS:
- break;
-
- case PRC_QUENCH:
- in_pcbnotify(&rdb,&sin->sin_addr,0,rdp_quench);
- break;
-
- /* close all affected connections */
- case PRC_HOSTDEAD:
- case PRC_HOSTUNREACH:
- case PRC_UNREACH_PROTOCOL:
- case PRC_UNREACH_NET:
- case PRC_UNREACH_HOST:
- in_pcbnotify(&rdb,&sin->sin_addr,(int)inetctlerrmap[cmd],rdp_fatal);
- break;
-
- case PRC_UNREACH_PORT:
- case PRC_UNREACH_NEEDFRAG:
- case PRC_UNREACH_SRCFAIL:
- break;
-
- case PRC_ROUTEDEAD:
- case PRC_REDIRECT_NET:
- case PRC_REDIRECT_HOST:
- case PRC_REDIRECT_TOSNET:
- case PRC_REDIRECT_TOSHOST:
- #ifdef BSD4_3
- in_pcbnotify(&rdb,&sin->sin_addr,0, in_rtchange);
- #endif
- break;
-
- default:
- panic("rdp_ctlinput");
- }
- }
-
- /**************************************************************************/
- /* cltoutput routine */
- /* again, only exercised by 4.3 */
- /**************************************************************************/
-
- rdp_ctloutput(op, so, level, optname, mp)
- int op;
- struct socket *so;
- int level, optname;
- struct mbuf **mp;
- {
-
- #ifdef notdef
-
- /* requires 4.3 */
- if (level != IPPROTO_RDP)
- return(ip_ctloutput(op,so,level,optname,mp));
- #endif
-
- /*
- * nothing yet
- *
- * should allow applications to choose window size information
- * before starting connection.
- */
-
- return(0);
- }
-
- /**************************************************************************/
- /* slowtimo -- state timer */
- /**************************************************************************/
-
- rdp_slowtimo()
- {
- int s = splnet();
- register i, j;
- register u_short timeout;
- register struct rdpque *rq;
- struct rdpcb *rp;
- struct inpcb *inp;
- struct mbuf *m;
- int flags;
-
- s = splnet();
-
- for(inp = rdb.inp_next; inp != &rdb; inp = inp->inp_next)
- {
- if ((rp = (struct rdpcb *)inp->inp_ppcb) == 0)
- continue;
-
- rq = rp->rp_rq;
-
- /* only do states we care about */
-
- switch (rp->rp_state)
- {
- /* trying to initiate connection */
- case R_SYN_SENT:
- case R_SYN_RCVD:
- if (++(rq->rq_sndtimer[0]) >= rdp_start[rq->rq_retries[0]])
- {
- if (++(rq->rq_retries[0]) >= rdp_tryinit)
- {
- inp->inp_socket->so_error = ETIMEDOUT;
- (void) rdp_fatal(inp);
- break;
- }
-
- if (rp->rp_state == R_SYN_SENT)
- {
- /* sndnxt = sndiss */
- (void) rdp_syn(inp,0,rp->rp_sndnxt,(u_long)0);
- }
- else
- {
- /* rcvcur == rcvirs , sndnxt = sndiss */
- (void) rdp_syn(inp,1,rp->rp_sndnxt,rp->rp_rcvcur);
- }
-
- }
- break;
-
- /* activity timer or packet timer */
- case R_OPEN:
- /* keepalive -- change to use if SO_KEEPALIVE requested? */
- if ((rp->rp_timer != 0) && (--(rp->rp_timer)==0))
- {
- /* don't need to reset the timer */
-
- rdp_info.rst_nulls++;
- (void) rdp_send(inp,(struct mbuf *)0);
- }
- /* fall thru... */
-
- case R_DRAIN:
- /* packet timers */
- i = rp->rp_sndnxt - rp->rp_snduna;
- j = rq->rq_sndbase;
- flags = inp->inp_socket->so_state & SS_PRIV;
-
- for(; i>0; i--)
- {
- if (rq->rq_sndq[j] == 0)
- goto next;
-
- timeout = (rq->rq_retries[j] + 1) * rp->rp_estrtt;
-
- if (++(rq->rq_sndtimer[j]) < timeout)
- goto next;
-
- /* too many tries?? */
- if (++(rq->rq_retries[j]) > R_MAXTRIES)
- {
- rdp_info.rst_conntimo++;
- inp->inp_socket->so_error = ETIMEDOUT;
- (void) rdp_fatal(inp);
- break;
- }
-
- if ((m=m_copy(rq->rq_sndq[j],0,(int)M_COPYALL))==0)
- goto next;
-
- rdp_info.rst_retrans++;
-
- (void)ip_output(m,(struct mbuf *)0,&(inp->inp_route),flags);
- next:
- if (++j == R_MAXSND)
- j = 0;
- }
- break;
-
-
- /* closing */
- case R_CLOSE_WAIT:
- if ((rp->rp_timer != 0) && (--(rp->rp_timer)==0))
- {
- rp->rp_state = R_CLOSED;
- (void) rdp_detach(inp->inp_socket,inp);
- }
- else if (rq->rq_retries[0] <= R_MAXTRIES)
- {
- timeout = rp->rp_estrtt * rq->rq_retries[0];
- if (++(rq->rq_sndtimer[0]) >= timeout)
- {
- rq->rq_retries[0]++;
- (void) rdp_rst(inp,0,rp->rp_sndnxt,(u_long)0,1);
- }
- }
- break;
- }
- }
-
- splx(s);
- }
-
- /**************************************************************************/
- /* fasttimo -- packet timer */
- /**************************************************************************/
-
- rdp_fasttimo()
- {
- int s;
-
- /* is this necessary? */
- s = splnet();
-
- rdpserial += 64; /* gross */
-
- splx(s);
- }
-